package com.wsx.ones.monitor.core.exec.push;

import com.wsx.ones.monitor.core.common.ChannelState;
import com.wsx.ones.monitor.core.loader.RpcClientLoader;
import com.wsx.ones.monitor.core.netty.PushChannelHander;
import com.wsx.ones.monitor.core.netty.PushMessageHandler;
import com.wsx.ones.monitor.core.serialize.RpcSerializeProtocol;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;

import java.net.InetSocketAddress;
import java.util.concurrent.Callable;

/**
 * 初始化netty客户端的核心实现
 * 链接netty服务端
 * 链接成功后将发送消息的句柄设置到对应的加载器中，供后期的客户端发送消息使用
 * Created by wangshuaixin on 17/2/6.
 */
public class PushInitTask implements Callable<Boolean> {

    private EventLoopGroup eventLoopGroup;
    private InetSocketAddress address;
    private RpcSerializeProtocol protocol;

    public PushInitTask (EventLoopGroup eventLoopGroup, InetSocketAddress address, RpcSerializeProtocol protocol) {
        this.eventLoopGroup = eventLoopGroup;
        this.address = address;
        this.protocol = protocol;
    }

    /**
     * 下面是netty的标准实现
     * 采用长连接的机制
     * @return
     * @throws Exception
     */
    @Override
    public Boolean call() throws Exception {
        //执行对netty的客户端操作
        Bootstrap bootstrap = new Bootstrap();

        //下面的参数需要在后期的升级开发中进行配置的功能升级
        bootstrap.group(eventLoopGroup)
                    .channel(NioSocketChannel.class)
                    .option(ChannelOption.SO_KEEPALIVE, true)
                    .option(ChannelOption.TCP_NODELAY, true)
                    .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 2000);

        //设置通道流，根据序列化的机制采用不同的管道流
        bootstrap.handler(new PushChannelHander(protocol));

        //链接服务端
        ChannelFuture future = null;
        try {
            future = bootstrap.connect(address);
        } catch (Exception e) {
            return false;
        }

        //设置服务器为正常状态
        RpcClientLoader.getInstance().setChannelState(ChannelState.ALIVE);

        //将发送消息的句柄设置到相应的类中，给系统提示可以进行消息发送
        future.addListener(new ChannelFutureListener() {
            @Override
            public void operationComplete(ChannelFuture channelFuture) throws Exception {
                //连接成功后的消息发送句柄
                RpcClientLoader.getInstance().setPushMessageHandler(
                        channelFuture.channel().pipeline().get(PushMessageHandler.class));
            }
        });
        return true;
    }
}
